home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 21 / Cream of the Crop 21 (Terry Blount) (October 1996).iso / program / libkb100.zip / LIBKB-1.00 / SRC / KBSIGNAL.C < prev    next >
C/C++ Source or Header  |  1996-07-23  |  12KB  |  571 lines

  1. /* kbsignal.c -- signal handling
  2.  * Copyright (C) 1995, 1996 Markus F.X.J. Oberhumer
  3.  * For conditions of distribution and use, see copyright notice in kb.h 
  4.  */
  5.  
  6. #include <signal.h>
  7. #include <errno.h>
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10.  
  11. #include <kb.h>
  12. #include "_kb.h"
  13.  
  14.  
  15. #if defined(KB_LOCK_ALL_START)
  16. KB_LOCK_ALL_START(_libkb_kbsignal)
  17. #endif
  18.  
  19.  
  20. /***********************************************************************
  21. // wrapper for djgpp v1
  22. ************************************************************************/
  23.  
  24. #if defined(_KB_NO_SIGNALS)
  25.  
  26. const int _kb_nsig = 0;
  27. const int _kb_sigmin = 0;
  28. const int _kb_sigmax = -1;
  29.  
  30. #if !defined(SIG_ERR)
  31. #  define SIG_ERR    NULL
  32. #endif
  33.  
  34. int _kb_signal_install(void)
  35. {
  36.     return 0;                /* installation ok */
  37. }
  38.  
  39. static void _my_signal_handler(int signum)
  40. {
  41.     _kb_emergency_remove(1);
  42.     exit(EXIT_SIG(signum));    
  43. }
  44.  
  45. const kb_sighandler_t kb_signal_handler = _my_signal_handler;
  46.  
  47. kb_sighandler_t kb_signal(int signum, kb_sighandler_t handler)
  48. {
  49.     return SIG_ERR;
  50. }
  51.  
  52. kb_sighandler_t kb_get_chained_signal(int signum)
  53. {
  54.     return SIG_ERR;
  55. }
  56.  
  57. kb_sighandler_t kb_set_chained_signal(int signum, kb_sighandler_t h)
  58. {
  59.     return SIG_ERR;
  60. }
  61.  
  62. #endif /* _KB_NO_SIGNALS */
  63.  
  64.  
  65. /***********************************************************************
  66. // IMPORTANT NOTE: check your compiler flags so that no
  67. //                 stack overflow checks will be inserted here !
  68. ************************************************************************/
  69.  
  70. #if !defined(_KB_NO_SIGNALS)
  71.  
  72. /* don't waste memory */
  73. #if defined(__DJGPP__)
  74. #  define KB_SIGMIN    288
  75. #else
  76. #  define KB_SIGMIN    0
  77. #endif
  78.  
  79. /* NSIG is the highest defined signal number + 1 */
  80. #if !defined(NSIG)
  81. #  if defined(_NSIG)
  82. #    define NSIG    _NSIG
  83. #  elif defined(SIGMAX)
  84. #    define NSIG    (SIGMAX+1)
  85. #  elif defined(_SIGMAX)
  86. #    define NSIG    (_SIGMAX+1)
  87. #  else
  88. #    define NSIG    (32 + KB_SIGMIN)
  89. #  endif
  90. #endif
  91.  
  92. const int _kb_nsig = NSIG;
  93. const int _kb_sigmin = KB_SIGMIN;
  94. const int _kb_sigmax = NSIG - 1;
  95.  
  96. /* sigaction() gives us more control than signal() */
  97. #if defined(__KB_LINUX)
  98. #  define _KB_USE_SIGACTION_GET
  99. #elif defined(__EMX__)
  100. #  define _KB_USE_SIGACTION_GET
  101. #  define _KB_USE_SIGACTION_SET
  102. #endif
  103.  
  104.  
  105. /***********************************************************************
  106. // wrappers for sigaction/signal
  107. ************************************************************************/
  108.  
  109. #if defined(_KB_USE_SIGACTION_GET)
  110. static kb_sighandler_t kb_signal_get_sa(int signum, struct sigaction *sa)
  111. {
  112.     if (sa == NULL)
  113.         return SIG_ERR;
  114.     if (sigaction(signum,NULL,sa) != 0)
  115.         return SIG_ERR;
  116.     return sa->sa_handler;
  117. }
  118. #endif
  119.  
  120.  
  121. #if defined(_KB_USE_SIGACTION_SET)
  122. static kb_sighandler_t kb_signal_set_sa(int signum, kb_sighandler_t h,
  123.                                         struct sigaction *sa)
  124. {
  125.     kb_sighandler_t oldh;
  126.  
  127.     if (sa == NULL)
  128.         return SIG_ERR;
  129.     if (sigaction(signum,NULL,sa) != 0)
  130.         return SIG_ERR;
  131.     oldh = sa->sa_handler;
  132.     if (oldh == SIG_ERR || h == SIG_ERR)
  133.         return SIG_ERR;
  134.     sa->sa_handler = h;
  135. #if defined(__EMX__)            /* use the emx signal processing model */
  136.     sa->sa_flags &= ~(SA_SYSV);
  137.     sa->sa_flags |= (SA_ACK);
  138. #endif
  139.     if (sigaction(signum,sa,NULL) != 0)
  140.         return SIG_ERR;
  141.     return oldh;
  142. }
  143. #endif
  144.  
  145.  
  146. static kb_sighandler_t kb_signal_get(int signum)
  147. {
  148. #if defined(_KB_USE_SIGACTION_GET)
  149.     struct sigaction sa;
  150.     return kb_signal_get_sa(signum,&sa);
  151. #else
  152.     kb_sighandler_t h;
  153.  
  154.     h = signal(signum,SIG_DFL);                    /* get and set handler */
  155.     if (h == SIG_ERR)                            /* error in signal() call */
  156.         return SIG_ERR;
  157.     if (h != SIG_DFL)
  158.         if (signal(signum,h) == SIG_ERR)        /* restore handler */
  159.             return SIG_ERR;
  160.     return h;
  161. #endif
  162. }
  163.  
  164.  
  165. static kb_sighandler_t kb_signal_set(int signum, kb_sighandler_t h)
  166. {
  167. #if defined(_KB_USE_SIGACTION_SET)
  168.     struct sigaction sa;
  169.     return kb_signal_set_sa(signum,h,&sa);
  170. #else
  171.     return signal(signum,h);
  172. #endif
  173. }
  174.  
  175.  
  176. /***********************************************************************
  177. // vars for the old (chained) signal handlers
  178. ************************************************************************/
  179.  
  180. /* don't waste memory */
  181. #define old_sigh        (__old_sigh - KB_SIGMIN)
  182. #define sig_installed    (__sig_installed - KB_SIGMIN)
  183.  
  184. #if defined(_KB_USE_SIGACTION_GET)
  185.    static struct sigaction __old_sigh[NSIG - KB_SIGMIN];
  186. #  define OLD_SIGH(signum)    (old_sigh[signum].sa_handler)
  187. #else
  188.    static kb_sighandler_t __old_sigh[NSIG - KB_SIGMIN];
  189. #  define OLD_SIGH(signum)    (old_sigh[signum])
  190. #endif
  191.  
  192. static unsigned char __sig_installed[NSIG - KB_SIGMIN];
  193.  
  194.  
  195.  
  196. /***********************************************************************
  197. // our signal handler
  198. ************************************************************************/
  199.  
  200. static void _my_signal_handler(int signum)
  201. {
  202.     int err;
  203.  
  204. #if defined(KB_DEBUG) && (KB_DEBUG >= 2)
  205.     /* remove keyboard handler before doing anything else */
  206.     _kb_emergency_remove(0);
  207.     
  208.     /* file I/O is somewhat dangerous within a signal handler ... */
  209.     fprintf(stderr,"libkb: received signal %d%s\n", signum,
  210.         (signum < KB_SIGMIN || signum >= NSIG) ? "  STRANGE !!!" : "");
  211.     fflush(stderr);
  212. #endif
  213.  
  214.     /* remove keyboard handler */
  215.     _kb_emergency_remove(1);
  216.  
  217.     /* sanity check */
  218.     if (signum < KB_SIGMIN || signum >= NSIG)
  219.         return;
  220.  
  221.     /* restore old signal handler */
  222.     if (sig_installed[signum] != 0x01)        /* should not happen */
  223.     {
  224.         err = (signal(signum,SIG_DFL) == SIG_ERR);
  225. #if defined(KB_DEBUG) && (KB_DEBUG >= 2)
  226.         fprintf(stderr,"libkb: signal %d not expected !!!\n", signum);
  227.         fflush(stderr);
  228. #endif
  229.     }
  230. #if defined(_KB_USE_SIGACTION_GET)
  231.     else if (sigaction(signum,&old_sigh[signum],NULL) != 0)
  232.         err = 1;
  233. #else
  234.     else if (signal(signum,old_sigh[signum]) == SIG_ERR)
  235.         err = 1;
  236. #endif
  237.     else
  238.         err = 0;
  239.  
  240. #if defined(__EMX__)            /* emx signal processing model */
  241.     signal(signum,SIG_ACK);        /* ack. signal */
  242. #endif
  243.  
  244.     /* chain old signal handler - this should terminate the program */
  245.     if (!err)
  246.     {
  247.         sig_installed[signum] = 0;        /* no longer active */
  248. #if defined(KB_DEBUG) && (KB_DEBUG >= 2)
  249.         fprintf(stderr,"libkb: chaining signal %d\n",signum);
  250.         fflush(stderr);
  251. #endif
  252.         raise(signum);
  253.     }
  254.  
  255.     /* if we return from here, the application should be aware
  256.      * that the keyboard handler was removed.
  257.      */
  258. }
  259.  
  260.  
  261. /* improve source code readability (at least a little bit :-) */
  262. #define MY_HANDLER        _my_signal_handler
  263.  
  264. /* make accessible */
  265. const kb_sighandler_t kb_signal_handler = MY_HANDLER;
  266.  
  267.  
  268. /***********************************************************************
  269. // install a signal handler (compatible to signal())
  270. ************************************************************************/
  271.  
  272. kb_sighandler_t kb_signal(int signum, kb_sighandler_t handler)
  273. {
  274.     kb_sighandler_t h;
  275.  
  276.     if (signum < KB_SIGMIN || signum >= NSIG || handler == SIG_ERR)
  277.         return SIG_ERR;
  278.     h = kb_signal_get(signum);
  279.     if (h == SIG_ERR)
  280.     {
  281.         sig_installed[signum] = 0x81;
  282.         return SIG_ERR;
  283.     }
  284.  
  285.     if (h == MY_HANDLER && sig_installed[signum] != 0x01)
  286.     {
  287.         /* strange: someone installed my handler without my knowledge */
  288.         sig_installed[signum] = 0x01;
  289.     }
  290.  
  291.     if (h == handler)                /* no change */
  292.         return h;
  293.  
  294.     if (handler != MY_HANDLER)        /* not my handler */
  295.     {
  296.         if (kb_signal_set(signum,handler) != h)
  297.             return SIG_ERR;
  298.         if (handler == SIG_IGN)
  299.             sig_installed[signum] = 0x20;
  300.         else
  301.             sig_installed[signum] = 0x10;
  302.         return h;
  303.     }
  304.  
  305.     /* are you still here ? :-) */
  306.     /* assert(handler == MY_HANDLER); */
  307.  
  308.     /* store current signal information */
  309. #if defined(_KB_USE_SIGACTION_GET)
  310.     if (kb_signal_get_sa(signum,&old_sigh[signum]) != h)
  311.         return SIG_ERR;
  312. #else
  313.     old_sigh[signum] = h;
  314. #endif
  315.  
  316.     /* if the signal is ignored, we ignore it as well */
  317.     if (h == SIG_IGN)
  318.     {
  319.         sig_installed[signum] = 0x02;
  320.         return h;
  321.     }
  322.  
  323.     /* now the time has come to install our handler */
  324.     if (kb_signal_set(signum,handler) != h)
  325.     {
  326.         sig_installed[signum] = 0x82;
  327.         return SIG_ERR;
  328.     }
  329.  
  330.     /* everything ok */
  331.     sig_installed[signum] = 0x01;
  332.     return h;
  333. }
  334.  
  335.  
  336. /***********************************************************************
  337. // install all signal handlers
  338. // note: a handler cannot be installed for SIGKILL, so 
  339. //       don't "kill -9" as this will not restore the keyboard
  340. ************************************************************************/
  341.  
  342. /* FIXME: which signals ? */
  343. /* We catch all signals that cause an exit by default (aka almo